type RequestCache = 'no-cache' | 'default' | 'force-cache' | 'no-store' | 'only-if-cached' | 'reload'
type RequestCredentials = 'same-origin' | 'include' | 'omit'
type RequestMode = 'same-origin' | 'cors' | 'navigate' | 'no-cors'
type RequestRedirect = 'follow' | 'error' | 'manual'

interface FetchConfig {
  cache?: RequestCache
  credentials?: RequestCredentials
  headers?: any
  mode?: RequestMode
  redirect?: RequestRedirect
  referrer?: string
  timeOut?:number
  requestType?:string
  baseUrl?:string
}

interface SendCofig {
  url:string
  params?:any
  method?:string
  headers:any
 }

//  interface ContentType {
//   headers:any
//   formatting:Function
//  }
class Fetch {
  config!:FetchConfig
  dataOperation!:any
  constructor (config:FetchConfig) {
    const defaultConfig:FetchConfig = {
      cache: 'no-cache', // * default, no-cache, reload, force-cache, only-if-cached
      credentials: 'same-origin', // include, same-origin, *omit
      headers: {},
      mode: 'cors', // no-cors, cors, *same-origin
      redirect: 'follow', // manual, *follow, error
      referrer: 'no-referrer', // *client, no-referrer
      timeOut: 30000,
      requestType: 'JSON',
      baseUrl: ''
    }
    this.config = {
      ...defaultConfig,
      ...config
    }

    this.dataOperation = {
      JSON: {
        headers: {
          'Content-Type': 'application/json' // 告诉服务器，我们提交的数据类型为 json 格式
        },
        formatting (params:any) {
          return JSON.stringify(params)
        }
      },
      FormData: {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded' // 告诉服务器，我们提交的数据类型为 FormData 格式
        },
        formatting (params:any) {
          const _formData = new FormData()
          Object.keys(params).forEach(key => {
            _formData.append(key, params[key])
          })
          return _formData
        }
      }
    }
  }

  preSend ({ url, params, method = 'GET', headers }:SendCofig) {
    const {
      cache,
      credentials,
      mode,
      redirect,
      referrer,
      requestType
    } = this.config
    const fetchConfig = {
      cache,
      credentials,
      mode,
      redirect,
      referrer,
      headers: {
        ...this.config.headers,
        ...headers
      },
      method,
      body: params ? this.dataOperation[<string>requestType].formatting(params) : null
    }
    return this.send(url, fetchConfig)
  }

  send (url:string, fetchConfig:any) {
    const ajax = new Promise((resolve) => {
      fetch(url, fetchConfig).then(res => {
        return res.json()
      }).then(data => {
        resolve(data)
      })
    })
    // 设置超时时间
    const time = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(new Error('time out'))
      }, this.config.timeOut)
    })
    return Promise.race([ajax, time])
  }

  /* send ({ url, params, method = 'GET', headers }:sendCofig) {
    const ajax = new Promise((resolve) => {
      const requestConfig = {
        ...this.config,
        body: params,
        method
      }
      requestConfig.headers = {
        ...requestConfig.headers,
        ...headers
      }

      fetch(url, {
        cache: requestConfig.cache,
        credentials: requestConfig.credentials,
        headers: requestConfig.headers,
        mode: requestConfig.mode,
        redirect: requestConfig.redirect,
        referrer: requestConfig.referrer
      }).then(res => {
        return res.json()
      }).then(data => {
        resolve(data)
      })
    })
    // 设置超时时间
    const time = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(new Error('time out'))
      }, this.config.timeOut)
    })

    return Promise.race([ajax, time])
  } */

  get ({ url, params, headers }:SendCofig) {
    let urlData = '?'
    for (const key in params) {
      urlData += `${key}=${params[key]}&`
    }
    return this.preSend({ url: `${url}${urlData}`, headers, method: 'GET' })
  }

  post ({ url, params, headers }:SendCofig) {
    return this.preSend({ url, params, headers, method: 'POST' })
  }
}

export default Fetch
